﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VRP_GTS
{
    class CVRPData
    {
        private TSPLIBParser myParser;

        public CVRPData(TSPLIBParser myParser)
        {
            this.myParser = myParser;
            BestKnownSolution = myParser.BestKnown;
            Capacity = myParser.Capacity;
            MaxLength = myParser.MaxLength;
            Coordinates = myParser.Vertices;
            Demands = myParser.Demands;
            Dimension = myParser.Dimension;
            Name = myParser.Name;

            CreateNodeList();
            CreateLinkMatrix();
            //CalculateDistanceMatrix();

            //Validate();
        }

        /// <summary>
        /// The name of the instance
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// The number of customers and the depot
        /// </summary>
        public int Dimension { get; private set; }

        /// <remarks>
        /// Distances computed from coordinates
        /// </remarks>
        public double[,] Distances { get; private set; }

        /// <summary>
        /// Coordinates read from file
        /// </remarks>
        private double[,] Coordinates { get; set; }

        /// <summary>
        /// The demand vector that specifies how many goods need to be delivered.
        /// The vector has to include the depot, but with a demand of 0.
        /// </summary>
        public double[] Demands { get; private set; }

        /// <summary>
        /// The capacity of the vehicles, which is the same for all (homogeneous fleet).
        /// </summary>
        public double Capacity { get; private set; }

        /// <summary>
        /// The total route length, which is the same for all (homogeneous fleet).
        /// Add by Will and Ying
        /// </summary>
        public double? MaxLength { get; private set; }

        /// <summary>
        /// Optional! The best-known solution.
        /// </summary>
        public double? BestKnownSolution { get; private set; }

        /// <summary>
        /// The list of all nodes, each node contains coordinates and demand info 
        /// </summary>
        public List<Node> NodeList { get; set; }

        /// <summary>
        /// The link matrix
        /// </summary>
        public Link[,] LinkMatrix { get; set; }

        /// <summary>
        /// The function to get the distance matrix
        /// </summary>
        public void CalculateDistanceMatrix()
        {
            Distances = new double[Dimension, Dimension];
            for (int i = 0; i < Dimension; i++)
            {
                for (int j = i + 1; j < Dimension; j++)
                {
                    Distances[i, j] = Link.GetLength(NodeList[i], NodeList[j]);
                    Distances[j, i] = Distances[i, j];
                }
            }
        }

        /// <summary>
        /// The function to create the NodeList
        /// </summary>
        public void CreateNodeList()
        {
            NodeList = new List<Node>();
            for (int i = 0; i < Dimension; i++)
                NodeList.Add(new Node(i, Coordinates[i, 0], Coordinates[i, 1], Demands[i]));
            CreateLinkMatrix();
        }


        /// <summary>
        /// The function to create the link matrix
        /// </summary>
        public void CreateLinkMatrix()
        {
            LinkMatrix = new Link[Dimension, Dimension];
            for (int i = 0; i < Dimension; i++)
            {
                for (int j = i + 1; j < Dimension; j++)
                {
                    LinkMatrix[i, j] = new Link(NodeList[i], NodeList[j]);
                    LinkMatrix[j, i] = new Link(NodeList[j], NodeList[i]);
                }
            }
        }
        /// <summary>
        /// Makes sure data makes sense
        /// </summary>
        internal void Validate()
        {
            if (Dimension < 1)
                throw new Exception("Dimension < 1");

            if (Distances.Length != Dimension * Dimension)
                throw new Exception("Distances.Length != Dimension * Dimension");

            if (Demands.Length != Dimension)
                throw new Exception("Demands.Length != Dimension");

            for (int i = 0; i < Dimension; i++)
            {
                if (Demands[i] < 0)
                    throw new Exception("Demands[" + i + "] < 0");

                if (Demands[i] == 0 && i > 0)
                    Console.WriteLine("WARNING: Demands[" + i + "] == 0");

                if (Demands[i] > Capacity)
                    throw new Exception("Demands[" + i + "] > Capacity");

                for (int j = i + 1; j < Dimension; j++)
                {
                    if (Distances[i, j] == 0)
                        Console.WriteLine("WARNING: Distances[" + i + "," + j + "] == 0");
                }
            }

            if (Capacity <= 0)
                throw new Exception("Capacity <= 0");

            Console.WriteLine("Data Validated");
        }
    }
}
